#!/usr/bin/perl

use strict;

package Lunmgr::Device;

use Carp;
use Data::Dumper;
use Sub::Installer;
{

  my $_fcount = 0;
  our %FIELDS = map {$_ => ++$_fcount}
                  qw(_uuid _lun  _wwn      _model _mpath _dev 
                     _size _path _mount_pt _name  _msa   _pstatus);

  my %_default_data = (_mount_pt => 'NONE',
                       _name     => 'FREE',
                    );
  sub new
  {
      my ($caller, %args) = @_;
      my $class = ref($caller) || $caller;

      my %defaults = ref($caller) ? %$caller : %_default_data;
      my $self = {};
      @$self{keys %defaults} = values %defaults;

      while (my ($key, $val) = each %args) {
          croak "Invalid argument to $class::new($key)"
              unless (exists $FIELDS{"_$key"});
          $self->{"_$key"} = $val;
      }

      bless $self, $class;

      $self;
  }

  sub AUTOLOAD {
      use vars '$AUTOLOAD';

      my ($self, $val) = @_;
      my $class = ref $self;

      if ($AUTOLOAD =~ /.*::set_(\w+)/) {
          my $attr = $1;
          croak "Invalid attribute $attr" unless (exists $FIELDS{"_$attr"});
          croak "No enough parameters" if (@_ < 2);
          $class->install_sub({ "set_$attr" => sub { 
                           croak "No enough parameters" if (@_ < 2);

                           $_[0]->{"_$attr"} = $_[1]; 
                           return;
                       }
                  });

          $self->{"_$attr"} = $val;
          return $self->{"_$attr"};
      }
      else {
          my $attr = $AUTOLOAD;
          $attr =~ s/.*:://;
          croak "Invalid attribute $attr" unless (exists $FIELDS{"_$attr"});

          $class->install_sub({ $attr => sub { $_[0]->{"_$attr"} }
                  });

          return $self->{"_$attr"};
      }
  }

  sub path { $_[0]->{_mount_pt} . "/" . $_[0]->{_name}; }
  
  sub DESTROY {}
  
  sub ToPrintStr
  {
      my ($self) = @_;
  
      my $model = $self->model; $model =~ s/_/ /g;
  
      my $str = sprintf "  Device name: %s, mounted under %s\n"
          . "  ----------------------------------------------------------\n"
          . "  Unique ID: %s\n"
          . "  Lun %s on %s (IP: %s [%s])\n",
            $self->name, 
            $self->mount_pt, 
            $self->uuid, 
            $self->lun, 
            $model,
            $self->msa->ips->[0], 
            $self->msa->name;
  
      if ($self->mpath) {
          $str .= sprintf "  DM-Multipath alias: %s, with paths [%s]\n"
                         ."  Path status: %s\n",
                        $self->mpath,
                        join(',', keys %{$self->pstatus}),
                        join(',', map { $_ . "->" . $self->pstatus->{$_} } 
                                      keys %{$self->pstatus});
      }
      else  {
          $str .= "  DM-Multipath alias:  - DEVICE NOT VISIBLE";
      }
  
      $str;
  }
  
  sub ToPrintXML
  {
      my ($self, $indent) = @_;
      $indent ||= '';
  
      my @pstatus = ('','');
      @pstatus = map { "<path name=\"" . $_ . "\">" 
                         . $self->pstatus->{$_} . "</path>" 
                    } keys %{$self->pstatus}
                if ($self->mpath);
  
      sprintf "$indent<lun id=\"%s\">\n"
            . "$indent  <device>%s</device>\n"
            . "$indent  <mpath>%s</mpath>\n"
            . "$indent  <paths>\n"
            . "$indent    %s\n"
            . "$indent    %s\n"
            . "$indent  </paths>\n"
            . "$indent  <mount_pt>%s</mount_pt>\n"
            . "$indent  <name>%s</name>\n"
            . "$indent</lun>",
              $self->lun, 
              $self->uuid,
              $self->mpath,
              $pstatus[0], 
              $pstatus[1],
              $self->mount_pt,
              $self->name;
  }
  
  sub ToTableStr
  {
      my ($self) = @_;
      sprintf "%s %s %s:%s %s %s",
            $self->uuid,
            $self->model,
            $self->wwn,
            $self->lun,
            $self->mount_pt,
            $self->name;
  }
  
  sub ToJbodStr
  {
      my ($self) = @_;
      sprintf "    - LUN: %d, /dev/%s [%s], %s",
              $self->lun,
              $self->dev,
              $self->mpath,
              $self->size;
  }
  
  sub ToJbodXML
  {
      my ($self, $indent) = @_;
      $indent ||= '';
  
      sprintf "$indent<lun id=\"%s\">\n"
            . "$indent  <device>%s</device>\n"
            . "$indent  <mpath>%s</mpath>\n"
            . "$indent  <size>%s</size>\n"
            . "$indent  <mount_pt>%s</mount_pt>\n"
            . "$indent  <name>%s</name>\n"
            . "$indent</lun>",
              $self->lun,
              $self->uuid,
              $self->mpath,
              $self->size,
              $self->mount_pt,
              $self->name;
  }
  
  sub ToString
  {
      my $self = $_[0];
  
      sprintf join(', ', map { "$_=%s" } keys %FIELDS),
              @$self{keys %FIELDS};
  }
  
  use overload q("") => \&ToString;
}

1;
